<p>To reduce the risk of cross-site scripting attacks, templating systems, such as <code>Twig</code>, <code>Django</code>, <code>Smarty</code>,
<code>Groovy's template engine</code>, allow configuration of automatic variable escaping before rendering templates. When escape occurs, characters
that make sense to the browser (eg: &lt;a&gt;) will be transformed/replaced with escaped/sanitized values (eg: &amp; lt;a&amp; gt; ).</p>
<p>Auto-escaping is not a magic feature to annihilate all cross-site scripting attacks, it depends on <a
href="https://twig.symfony.com/doc/3.x/filters/escape.html">the strategy applied</a> and the context, for example a "html auto-escaping" strategy
(which only transforms html characters into <a href="https://developer.mozilla.org/en-US/docs/Glossary/Entity">html entities</a>) will not be relevant
when variables are used in a <a href="https://en.wikipedia.org/wiki/HTML_attribute">html attribute</a> because '<code>:</code>' character is not
escaped and thus an attack as below is possible:</p>
<pre>
&lt;a href="{{ myLink }}"&gt;link&lt;/a&gt; // myLink = javascript:alert(document.cookie)
&lt;a href="javascript:alert(document.cookie)"&gt;link&lt;/a&gt; // JS injection (XSS attack)
</pre>
<h2>Ask Yourself Whether</h2>
<ul>
  <li> Templates are used to render web content and
    <ul>
      <li> dynamic variables in templates come from untrusted locations or are user-controlled inputs </li>
      <li> there is no local mechanism in place to sanitize or validate the inputs. </li>
    </ul>  </li>
</ul>
<p>There is a risk if you answered yes to any of those questions.</p>
<h2>Recommended Secure Coding Practices</h2>
<p>Enable auto-escaping by default and continue to review the use of inputs in order to be sure that the chosen auto-escaping strategy is the right
one.</p>
<h2>Sensitive Code Example</h2>
<p><a href="https://www.npmjs.com/package/mustache">mustache.js</a> template engine:</p>
<pre>
let Mustache = require("mustache");

Mustache.escape = function(text) {return text;}; // Sensitive

let rendered = Mustache.render(template, { name: inputName });
</pre>
<p><a href="https://www.npmjs.com/package/handlebars">handlebars.js</a> template engine:</p>
<pre>
const Handlebars = require('handlebars');

let source = "&lt;p&gt;attack {{name}}&lt;/p&gt;";

let template = Handlebars.compile(source, { noEscape: true }); // Sensitive
</pre>
<p><a href="https://www.npmjs.com/package/markdown-it">markdown-it</a> markup language parser:</p>
<pre>
const markdownIt = require('markdown-it');
let md = markdownIt({
  html: true // Sensitive
});

let result = md.render('# &lt;b&gt;attack&lt;/b&gt;');
</pre>
<p><a href="https://www.npmjs.com/package/marked">marked</a> markup language parser:</p>
<pre>
const marked = require('marked');

marked.setOptions({
  renderer: new marked.Renderer(),
  sanitize: false // Sensitive
});

console.log(marked("# test &lt;b&gt;attack/b&gt;"));
</pre>
<p><a href="https://www.npmjs.com/package/kramed">kramed</a> markup language parser:</p>
<pre>
let kramed = require('kramed');

var options = {
  renderer: new kramed.Renderer({
    sanitize: false // Sensitive
  })
};
</pre>
<h2>Compliant Solution</h2>
<p><a href="https://www.npmjs.com/package/mustache">mustache.js</a> template engine:</p>
<pre>
let Mustache = require("mustache");

let rendered = Mustache.render(template, { name: inputName }); // Compliant autoescaping is on by default
</pre>
<p><a href="https://www.npmjs.com/package/handlebars">handlebars.js</a> template engine:</p>
<pre>
const Handlebars = require('handlebars');

let source = "&lt;p&gt;attack {{name}}&lt;/p&gt;";
let data = { "name": "&lt;b&gt;Alan&lt;/b&gt;" };

let template = Handlebars.compile(source); // Compliant by default noEscape is set to false
</pre>
<p><a href="https://www.npmjs.com/package/markdown-it">markdown-it</a> markup language parser:</p>
<pre>
let md = require('markdown-it')(); // Compliant by default html is set to false

let result = md.render('# &lt;b&gt;attack&lt;/b&gt;');
</pre>
<p><a href="https://www.npmjs.com/package/marked">marked</a> markup language parser:</p>
<pre>
const marked = require('marked');

marked.setOptions({
  renderer: new marked.Renderer()
}); // Compliant by default sanitize is set to true

console.log(marked("# test &lt;b&gt;attack/b&gt;"));
</pre>
<p><a href="https://www.npmjs.com/package/kramed">kramed</a> markup language parser:</p>
<pre>
let kramed = require('kramed');

let options = {
  renderer: new kramed.Renderer({
    sanitize: true // Compliant
  })
};

console.log(kramed('Attack [xss?](javascript:alert("xss")).', options));
</pre>
<h2>See</h2>
<ul>
  <li> OWASP - <a href="https://owasp.org/Top10/A03_2021-Injection/">Top 10 2021 Category A3 - Injection</a> </li>
  <li> <a href="https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.md">OWASP Cheat
  Sheet</a> - XSS Prevention Cheat Sheet </li>
  <li> OWASP - <a href="https://owasp.org/www-project-top-ten/2017/A7_2017-Cross-Site_Scripting_(XSS)">Top 10 2017 Category A7 - Cross-Site Scripting
  (XSS)</a> </li>
  <li> CWE - <a href="https://cwe.mitre.org/data/definitions/79">CWE-79 - Improper Neutralization of Input During Web Page Generation ('Cross-site
  Scripting')</a> </li>
</ul>
